<?php
/**
 * DMFramework
 * 
 * @license Copyright 2012 Dillen Meijboom under the Apache license version 2.0 (http://apache.org/licenses/LICENSE-2.0)
 * @author Dillen Meijboom <info@dillenm.nl>
 * @url http://dmframework.nl
 */

/**
 * The FTP class
 * 
 * @license Copyright 2012 Dillen Meijboom under the Apache license version 2.0 (http://apache.org/licenses/LICENSE-2.0)
 * @author Dillen Meijboom <info@dillenm.nl>
 * @package System.Library
 */
class Dmf_Ftp
{
    /**
     * The FTP connection resource
     * 
     * @var resource 
     */
    private $_connection = false;
    
    /**
     * FTP login data
     * 
     * @var array 
     */
    private $_ftpLogin = array();
    
    /**
     * Constructor
     * 
     * Only save the login data, only connect when needed!
     * 
     * @param string $server
     * @param string $username
     * @param string $password
     * @param int $port
     * @param boolean $ssl 
     */
    public function __construct( $server, $username, $password, $port = '21', $ssl = false )
    {
        $this->_ftpLogin = array(
            'server'    => $server,
            'username'  => $username,
            'password'  => $password,
            'port'      => $port,
            'ssl'       => (boolean)$ssl
        );
    }
    
    /**
     * Get connection (and connect if not connected yet)
     * 
     * @return resource
     * @throws Exception 
     */
    public function getCon()
    {
        if ( $this->_connection !== false )
        {
            return $this->_connection;
        }
        
        if ( $this->_ftpLogin['ssl'] === true )
        {
            $ftp = @ftp_ssl_connect( $this->_ftpLogin['server'], $this->_ftpLogin['port'], 3 );
        }
        else
        {
            $ftp = @ftp_connect( $this->_ftpLogin['server'], $this->_ftpLogin['port'], 3 );
        }
        
        if ( ! $ftp )
        {
            throw new Exception( 'Could not connect to FTP server: "' . $this->_ftpLogin['server'] . '" port "' . $this->_ftpLogin['port'] . '".' );
        }
        
        $login = @ftp_login( $ftp, $this->_ftpLogin['username'], $this->_ftpLogin['password'] );
        
        if ( ! $login )
        {
            throw new Dmf_Exception_ServerLogin( 'Could not login to FTP server: "' . $this->_ftpLogin['server'] . '" port "' . $this->_ftpLogin['port'] . '" using user: "' . $this->_ftpLogin['username'] . '".' );
        }
        
        $this->_connection = $ftp;
    }
    
    /**
     * Download a file from FTP
     * 
     * @param string $remote_file
     * @param string $local_file
     * @param int $mode
     * @return boolean 
     */
    public function download( $remote_file, $local_file, $mode = FTP_ASCII )
    {
        $fp = @fopen( $local_file, 'w+' );
        
        $result = @ftp_fget( $this->getCon(), $fp, $remote_file, $mode, 0 );
        
        fclose( $fp );
        
        return $result;
    }
    
    /**
     * Get the remote filesize
     * 
     * @param string $remote_file
     * @return int
     */
    public function filesize( $remote_file )
    {
        return ftp_size( $this->getCon(), $remote_file );
    }
    
    /**
     * Chmod a remote FTP file
     * 
     * @param string $path
     * @param int $rights
     * @return boolean 
     */
    public function chmod( $path, $rights )
    {
        $rights = ( substr( $rights, 0, 1 ) == 0 ? $rights : '0' . $rights );
        
        return @ftp_chmod( $this->getCon(), $path, octdec( $rights ) );
    }
    
    /**
     * Upload a file
     * 
     * @param string $remote_file
     * @param string $local_file
     * @param int $mode
     * @return boolean
     * @throws Exception 
     */
    public function upload( $remote_file, $local_file, $mode = FTP_ASCII )
    {
        if ( ! file_exists( $local_file ) )
        {
            throw new Exception( 'Can not upload FTP file: "' . $local_file . '" file does not exist or isn\'t readable.' );
        }
        
        $fp = @fopen( $local_file, 'r' );
        
        $result = @ftp_fput( $this->getCon(), $remote_file, $fp, $mode, 0 );
        
        fclose( $fp );
        
        return $result;
    }
    
    /**
     * Unlink a remote FTP file
     * 
     * @param string $path
     * @return boolean 
     */
    public function delete( $path )
    {
        return @ftp_delete( $this->getCon(), $path );
    }
    
    /**
     * Shortcut -> $this->delete
     */
    public function unlink( $path )
    {
        return $this->delete( $path );
    }
    
    /**
     * Rename a file or directory on a FTP server
     * 
     * @param string $from
     * @param string $to
     * @return boolean
     */
    public function rename( $from, $to )
    {
        return @ftp_rename( $this->getCon(), $from, $to );
    }
    
    /**
     * Execute a command
     * 
     * @param string $command
     * @return boolean 
     */
    public function command( $command )
    {
        if ( ( $response = @ftp_exec( $this->getCon(), $command ) ) )
        {
            return $response;
        }
        else
        {
            return false;
        }
    }
    
    /**
     * Get file list
     * 
     * @param string $dir
     * @return array 
     */
    public function getList( $dir )
    {
        return @ftp_nlist( $this->getCon(), $dir );
    }
    
    /**
     * Get current directory
     * 
     * @return string
     */
    public function pwd()
    {
        return @ftp_pwd( $this->getCon() );
    }
    
    /**
     * Change directory
     * 
     * @param string $dir
     * @return boolean
     */
    public function chdir( $dir )
    {        
        return ( @ftp_chdir( $this->getCon(), $dir ) === false ) ? false : @ftp_pwd( $this->getCon() );
    }
    
    /**
     * Shortcut -> $this->chdir
     */
    public function cd( $dir )
    {
        return $this->chdir( $dir );
    }
    
    /**
     * Go up one directory
     * 
     * @return boolean
     */
    public function cdup()
    {
        return @ftp_cdup( $this->getCon() );
    }
    
    /**
     * Shortcut -> $this->mkdir
     */
    public function md( $dir )
    {
        return @ftp_mkdir( $this->getCon(), $dir );
    }
    
    /**
     * Create directory on a FTP server
     * 
     * @param string $dir
     * @return boolean 
     */
    public function mkdir( $dir )
    {
        return $this->md( $dir );
    }
    
    /**
     * Shortcut -> $this->rmdir
     */
    public function rm( $dir )
    {
        if( ! ( @ftp_rmdir( $this->getCon(), $dir ) || @ftp_delete( $this->getCon(), $dir ) ) )
        {
            $filelist = @ftp_nlist( $this->getCon(), $dir );
            
            if ( ! $filelist )
            {
                return;
            }
            
            foreach( $filelist as $file )
            {
                if ( substr( $file, -2, strlen( $file) ) == '/.' || substr( $file, -3, strlen( $file ) ) == '/..' )
                {
                    continue;
                }
                
                $this->rm( $file );
            }
            
            $this->rm( $dir );
        }
    }
    
    /**
     * Remove a directory
     * 
     * @param string $dir
     * @return boolean
     */
    public function rmdir( $dir )
    {
        return $this->rm( $dir );
    }
    
    /**
     * Get file size from FTP file
     * 
     * @param string $path
     * @return boolean
     */
    public function getSize( $path )
    {
        return @ftp_size( $this->getCon(), $path );
    }
    
    /**
     * Close the FTP connection but only when there is one.
     * 
     * @return null 
     */
    public function close()
    {
        if ( $this->_connection === false )
        {
            return;
        }
        
        ftp_close( $this->getCon() );
    }
}